﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Elsa.JavaScript.Models;
using Elsa.Workflows;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using T.FAS.Runtime.MF.Activities;
using T.FAS.Runtime.MF.Activities.Helper;
using T.FAS.Runtime.MF.Entity;
using T.FAS.Runtime.MF.SPI;
using ElsaExpression = Elsa.Expressions.Models.Expression;

namespace T.FAS.Runtime.MF.Activities.Nodes
{
    internal class CdoNode : NodeBase, INodeMapper
    {
        [JsonProperty("data")]
        public new CdoNodeData Data { get; set; }
        public List<Variable> Variables { get; set; } = new List<Variable>();
        public List<OutputDefinition> Outputs { get; set; }
        public List<InputDefinition> Inputs { get; set; } = new List<InputDefinition>();
        public override List<UserVariable> NodeInputOutputVariables
        {
            get
            {
                if (Data.OutputVariables == null) return new List<UserVariable>();
                Data.OutputVariables.ForEach(v =>
                {
                    SetVariableInfo(v);
                });
                return Data.OutputVariables;
            }
        }

        private void SetVariableInfo(UserVariable v)
        {
            if (string.IsNullOrEmpty(v.ActivityID))
            {
                v.ActivityID = Id;
                v.CompositeVarName = $"{Id}:{v.VariableName}";
                v.CompositeVarName = v.CompositeVarName.Replace("-", "").Replace(":", "");
            }

        }
        public IActivity MapToActivity()
        {
            var activity = new CDOActivity() { Id = Id, Name = Data.Label };

            var cdoParams = Data.Operation.Params;
            //action的操作
            var actionType = Data.Operation.MetaData.Code;
            //CDO的Code
            var cdoId = Data.CdoCode;
            var activityOutputVariables = new Dictionary<string, Variable>();

            //CDO的action对应的参数列表
            var cdoMetaParams = Data.Operation.MetaData.ExprFuncItemParamList;

            //将节点的输出变量，放到elsa的变量列表中
            foreach (var varItem in (Data.OutputVariables ?? new List<UserVariable>()))
            {
                SetVariableInfo(varItem);
                var variable = VariableHelper.GenerateVariable(varItem);
                Variables.Add(variable);
                activityOutputVariables.Add(varItem.VariableName,variable);

                //为了向迭代节点返回值，此处特意增加一个变量，用于处理节点的返回值数组
                var iterationResultVarItem = new UserVariable() { CompositeVarName = $"{varItem.CompositeVarName}{MFConst.IterationResultVariableSuffix}", Type = varItem.ValueType };
                var iterationResultVar = VariableHelper.GenerateVariable(iterationResultVarItem);
                Variables.Add(iterationResultVar);

            }

            ProcessParamList(activity, cdoParams, cdoMetaParams);
            activity.ActionType = actionType;
            activity.CDOID = cdoId;
            activity.Metadata = DesignerMeta;
            activity.OutputVariables = activityOutputVariables;
            //正常执行的输出端口
            activity.DoneOutcomes = Ports.Items.Where(t => t.Group.ToLower() == "out").Select(t => t.Id).ToList();
            //异常执行的输出端口
            activity.ExceptionOutcomes = Ports.Items.Where(t => t.Group.ToLower() == "exception").Select(t => t.Id).ToList();

            return activity;
        }

        private void ProcessParamList(CDOActivity activity, Dictionary<string, object> cdoParams, List<ExprFuncItemParamNodeData> cdoMetaParams)
        {
            var paramList = cdoMetaParams.Where(t => t.Code != "CDOCode");

            if (paramList.Count() > 0)
            {
                activity.ParamList = new List<BranchCondition>();
                foreach (var item in paramList)
                {
                    object paramValue = "";
                    var expression = string.Empty;

                    if (cdoParams.ContainsKey(item.Code))
                    {
                        paramValue = cdoParams[item.Code];
                        expression = ParseParamExpression(paramValue);
                        activity.ParamList.Add(new BranchCondition { Label = item.Code, Condition = JavaScriptExpression.Create(expression) });
                    }
                    /*
                    //字符串
                    if (item.DataType == 9)
                    {
                        activity.ParamList.Add(new BranchCondition { Label = item.Code, Condition = ElsaExpression.LiteralExpression(paramValue) });
                    }
                    //对象
                    else if (item.DataType == 10)
                    {
                        var liquidExpression = string.Empty;
                        //变量是个表达式
                        if (IsLiquidExpression(paramValue.ToString(), out liquidExpression))
                        {
                            activity.ParamList.Add(new BranchCondition { Label = item.Code, Condition = JavaScriptExpression.Create(ParseJavaScriptExpression(liquidExpression)) });
                        }
                        else
                        {
                            activity.ParamList.Add(new BranchCondition { Label = item.Code, Condition = ElsaExpression.LiteralExpression(paramValue.ToString()) });

                        }
                    }
*/
                }
            }
        }

        private string ParseParamExpression(object paramValue)
        {
            string nodeId = string.Empty, variableId = string.Empty, variable = string.Empty, type = string.Empty;
            var expression = string.Empty;

            var obj = JObject.Parse(JsonConvert.SerializeObject(paramValue));
            if (obj.ContainsKey("nodeId"))
            {
                nodeId = obj["nodeId"].ToString();
            }
            if (obj.ContainsKey("variableId"))
            {
                variableId = obj["variableId"].ToString();
            }
            if (obj.ContainsKey("variable"))
            {
                variable = obj["variable"].ToString();
              
            }
            if (obj.ContainsKey("type"))
            {
                type = obj["type"].ToString();
            }

            if (nodeId.StartsWith("iteration"))
            {
                if (variable == "item")
                {
                    variable = "CurrentValue";
                }
                else if (variable == "index")
                {
                    variable = "CurrentIndex";
                }
            }

            variable = ActivityHelper.GetSourceVariableRealName(this, variable, nodeId);
            expression = ActivityHelper.GetVariableExpression(variable, type,false);
            //var varSelectors = variable.Split('.');
            //var varItem = varSelectors[0];
            //var varInfo = (this.BelongTo.NodeInputOutputVariables ?? new List<UserVariable>()).Find(t => t.VariableName == varItem && t.ActivityID == nodeId);
            //if (varInfo != null)
            //{
            //    var varName = varInfo.CompositeVarName;
            //    varSelectors[0] = varName;
            //    variable = string.Join(".", varSelectors);
            //}

            //if (varSelectors.Length > 1 || (varSelectors.Count() == 1 && type.ToLower() == "record"))
            //{
            //    expression = $"let {varItem} = JSON.parse(variables.{varItem});{varItem};";
            //}
            //else
            //{
            //    expression = $"let {varItem} = variables.{varItem};{varItem};";
            //}
            return expression;
        }
        //private string ParseJavaScriptExpression(string liquidExpression)
        //{
        //    var sbScript = new StringBuilder();

        //    var varName = liquidExpression.Split('.')[0];
        //    sbScript.AppendLine($"let {varName} = JSON.stringify(variables.{varName});");
        //    sbScript.AppendLine($"{liquidExpression}");

        //    return sbScript.ToString();
        //}
        //private bool IsLiquidExpression(string expression, out string liquidString)
        //{
        //    liquidString = expression;
        //    if (expression.StartsWith("{{") && expression.EndsWith("}}"))
        //    {
        //        liquidString = expression.Replace("{{", "").Replace("}}", "");
        //        return true;
        //    }
        //    else
        //    {
        //        var expressionObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(expression);
        //        var activityId = expressionObj.ContainsKey("nodeId") ? expressionObj["nodeId"] : "";
        //        var varName = expressionObj.ContainsKey("variableKeyCode") ? expressionObj["variableKeyCode"] : "";
        //        //从整个工作流中获取应的变量信息
        //        var varInfo = (this.BelongTo.NodeInputOutputVariables??new List<UserVariable>()).Find(t => t.VariableName == varName && t.ActivityID == activityId);
        //        liquidString = varInfo.CompositeVarName;
        //        return true;
        //    }
        //    return false; ;
        //}
    }

    public class CdoNodeData
    {
        [JsonProperty("label")]
        public string Label { get; set; }

        [JsonProperty("description")]
        public string Description { get; set; }

        [JsonProperty("cdoId")]
        public string CdoID { get; set; }
        [JsonProperty("cdoName")]
        public string CdoName { get; set; }
        [JsonProperty("cdoCode")]
        public string CdoCode { get; set; }
        [JsonProperty("operation")]
        public OperationNodeData Operation { get; set; }
        [JsonProperty("outputFields")]
        public List<UserVariable> OutputVariables { get; set; }
    }
    public class OperationNodeData
    {
        [JsonProperty("params")]
        public Dictionary<string, object> Params { get; set; }

        [JsonProperty("code")]
        public string Code { get; set; }

        [JsonProperty("funcSign")]
        public string FuncSign { get; set; }

        [JsonProperty("metaData")]
        public MetaDataNodeData MetaData { get; set; }
    }

   
    public class MetaDataNodeData
    {
        [JsonProperty("ID")]
        public string ID { get; set; }

        [JsonProperty("DisplayName")]
        public string DisplayName { get; set; }

        [JsonProperty("Name")]
        public string Name { get; set; }
        [JsonProperty("Code")]
        public string Code { get; set; }

        [JsonProperty("Description")]
        public string Description { get; set; }

        [JsonProperty("ItemType")]
        public string ItemType { get; set; }
        [JsonProperty("ValueType")]
        public string ValueType { get; set; }
        [JsonProperty("ExprFuncItemParamList")]
        public List<ExprFuncItemParamNodeData> ExprFuncItemParamList { get; set; }
    }

    public class ExprFuncItemParamNodeData
    {
        [JsonProperty("ID")]
        public string ID { get; set; }

        [JsonProperty("Name")]
        public string Name { get; set; }

        [JsonProperty("Code")]
        public string Code { get; set; }

        [JsonProperty("DataType")]
        public int DataType { get; set; }

        [JsonProperty("IsEmpty")]
        public string IsEmpty { get; set; }
        [JsonProperty("DefaultValue")]
        public string DefaultValue { get; set; }
        [JsonProperty("ExprExt")]
        public string ExprExt { get; set; }
    }
}
